﻿using Devonline.AspNetCore;
using Devonline.Core;
using FaceRecognitionDotNet;
using Microsoft.Extensions.Logging;

namespace Devonline.AuxiliaryTools.AITools;

/// <summary>
/// 面部识别服务
/// </summary>
public class FaceRecognitionService(ILogger<FaceRecognitionService> logger, IFaceRecognitionEndpoint endpoint) : IFaceRecognitionService
{
    private readonly ILogger<FaceRecognitionService> _logger = logger;
    private readonly IFaceRecognitionEndpoint _endpoint = endpoint;
    private readonly FaceRecognition _faceRecognition = FaceRecognition.Create(endpoint.Path);

    /// <summary>
    /// 人脸比对
    /// </summary>
    /// <param name="src">原始面部图片</param>
    /// <param name="dist">目标面部图片</param>
    /// <returns></returns>
    public async Task<(bool, float)> CompareAsync(string src, string dist)
    {
        _logger.LogInformation($"将使用 DlibDotNet 库比较两张面部照片: {src} 和 {dist} 的相似度");

        using var srcImage = GetImageFile(src);
        using var distImage = GetImageFile(dist);
        var faceEncodings = _faceRecognition.FaceEncodings(srcImage);
        if (faceEncodings is null || !faceEncodings.Any())
        {
            throw new ArgumentException($"原始图片 {src} 未能加载编码结果");
        }

        using var srcFaceEncoding = faceEncodings.FirstOrDefault();
        faceEncodings = _faceRecognition.FaceEncodings(distImage);
        if (faceEncodings is null || !faceEncodings.Any())
        {
            throw new ArgumentException($"目标图片 {dist} 未能加载编码结果");
        }

        using var distFaceEncoding = faceEncodings.FirstOrDefault();
        var score = FaceRecognition.FaceDistance(srcFaceEncoding, distFaceEncoding);
        var result = score <= _endpoint.FaceCompareThresholdValue;
        _logger.LogInformation($"使用 DlibDotNet 库比较两张面部照片: {src} 和 {dist} 的相似度, 比较完成, 人脸比对得分: {score} " + (result ? $"低于阈值: {_endpoint.FaceCompareThresholdValue}, 判定为同一人!" : $"高于阈值: {_endpoint.FaceCompareThresholdValue}, 判定为不是同一人!"));

        await Task.CompletedTask;
        return (result, (float)score);
    }

    /// <summary>
    /// 获取图片文件
    /// </summary>
    /// <param name="path"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentException"></exception>
    protected Image GetImageFile(string path)
    {
        var fileInfo = new FileInfo(path);
        if (!fileInfo.Exists)
        {
            throw new ArgumentException($"图片文件 {path} 不存在!");
        }

        if (fileInfo.Length > _endpoint.ImageLimit.Length)
        {
            throw new ArgumentException($"图片文件大小: {fileInfo.Length.GetByteSizeDetail()} 超过限制大小: {_endpoint.ImageLimit.Length.GetByteSizeDetail()}!");
        }

        var extensions = _endpoint.ImageLimit.Extensions.ToUpperInvariant().Split(AppSettings.CHAR_COMMA, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var extension = fileInfo.Extension.ToUpperInvariant();
        if (!extensions.Any(x => x == extension))
        {
            throw new ArgumentException($"不支持的图片类型: {fileInfo.Extension}, 仅支持: {_endpoint.ImageLimit.Extensions}!");
        }

        return FaceRecognition.LoadImageFile(path) ?? throw new ArgumentException($"未能加载图片 {path}");
    }
}